import type {YMapIndoorLevel, YMapIndoorPlan} from '@yandex/ymaps3-types/modules/layers-extra';
import {boundsAreEqual, fetchRoute, PreparedRouteData, prepareRawData} from '../common';
import {
    ACTIVE_FEATURE_STYLE,
    END_WAYPOINT,
    INIT_LEVEL_ID,
    LOCATION,
    MALL_BOUNDS,
    PASSIVE_FEATURE_STYLE,
    START_WAYPOINT
} from '../variables';

window.map = null;

main();
async function main() {
    const [ymaps3React] = await Promise.all([ymaps3.import('@yandex/ymaps3-reactify'), ymaps3.ready]);
    const reactify = ymaps3React.reactify.bindTo(React, ReactDOM);
    const {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer, YMapFeature, YMapControls, YMapControl} =
        reactify.module(ymaps3);
    const {YMapIndoorSchemeLayer} = reactify.module(await ymaps3.import('@yandex/ymaps3-layers-extra'));
    const {YMapDefaultMarker} = reactify.module(await ymaps3.import('@yandex/ymaps3-default-ui-theme'));

    function LevelsControl(props: {
        levels: YMapIndoorLevel[];
        activeLevelId: string;
        onClick: (level: YMapIndoorLevel) => void;
    }) {
        return (
            <YMapControls position="left">
                <YMapControl transparent={true}>
                    <div className="level-control">
                        {props.levels.map((level) => {
                            const className = `${level.id === props.activeLevelId ? 'active' : ''}`;
                            return (
                                <button key={level.id} className={className} onClick={() => props.onClick(level)}>
                                    {level.name}
                                </button>
                            );
                        })}
                    </div>
                </YMapControl>
            </YMapControls>
        );
    }

    function App() {
        const [currentPlans, setCurrentPlans] = React.useState<YMapIndoorPlan[]>([]);
        const [activeLevelId, setActiveLevelId] = React.useState<string>(INIT_LEVEL_ID);
        const [routeData, setRouteData] = React.useState<PreparedRouteData>();

        React.useEffect(() => {
            fetchRoute([START_WAYPOINT, END_WAYPOINT]).then((rawData) => {
                const preparedData = prepareRawData(rawData);
                setRouteData(preparedData);
            });
        }, []);

        const onSelectLevel = React.useCallback((level: YMapIndoorLevel) => setActiveLevelId(level.id), []);

        const indoorPlanChanged = React.useCallback(
            (plans: YMapIndoorPlan[]) => {
                setCurrentPlans(plans.filter(({bounds}) => boundsAreEqual(bounds, MALL_BOUNDS)));
            },
            [currentPlans]
        );

        const activePlans = React.useMemo(
            () => currentPlans.map((plan) => ({id: plan.id, levelId: activeLevelId})),
            [currentPlans, activeLevelId]
        );

        const showLevelControl = React.useMemo(() => currentPlans.length > 0, [currentPlans]);

        const levels = React.useMemo(() => {
            const actualLevels = currentPlans
                .map((plan) => plan.levels)
                .flat()
                .sort((a, b) => Number(b.id) - Number(a.id));
            const uniqLevels = _.uniqBy(actualLevels, 'id');
            return uniqLevels;
        }, [currentPlans]);

        const routeFeatures = React.useMemo(() => {
            if (!routeData) return [];

            const features = routeData.lines.map(({geometry, levelId}, index) => {
                const style = levelId === activeLevelId ? ACTIVE_FEATURE_STYLE : PASSIVE_FEATURE_STYLE;
                return <YMapFeature key={`line-${levelId}-${index}`} geometry={geometry} style={style} />;
            });

            const markers = routeData.connectors
                .filter(({levelId}) => levelId === activeLevelId)
                .map(({coordinates, icon, levelId}, index) => {
                    return (
                        <YMapDefaultMarker
                            key={`connector-${levelId}-${index}`}
                            coordinates={coordinates}
                            iconName={icon}
                        />
                    );
                });
            return [...features, ...markers];
        }, [routeData, activeLevelId]);

        return (
            // Initialize the map and pass initialization parameters
            <YMap location={reactify.useDefault(LOCATION)} showScaleInCopyrights={true} ref={(x) => (map = x)}>
                {/* Add a map scheme layer */}
                <YMapDefaultFeaturesLayer />
                <YMapDefaultSchemeLayer />
                <YMapIndoorSchemeLayer onIndoorPlansChanged={indoorPlanChanged} activePlans={activePlans} />

                {showLevelControl && (
                    <LevelsControl levels={levels} activeLevelId={activeLevelId} onClick={onSelectLevel} />
                )}

                {(START_WAYPOINT.level === undefined || activeLevelId === START_WAYPOINT.level) && (
                    <YMapDefaultMarker
                        key="start"
                        iconName="fallback"
                        coordinates={START_WAYPOINT.coordinates}
                        title="start"
                        zIndex={1000}
                    />
                )}
                {(END_WAYPOINT.level === undefined || activeLevelId === END_WAYPOINT.level) && (
                    <YMapDefaultMarker
                        key="end"
                        iconName="fallback"
                        coordinates={END_WAYPOINT.coordinates}
                        title="finish"
                        zIndex={1000}
                    />
                )}

                {routeFeatures}
            </YMap>
        );
    }

    ReactDOM.render(
        <React.StrictMode>
            <App />
        </React.StrictMode>,
        document.getElementById('app')
    );
}
